/****************************************************************************
 * Copyright (C) 2012
 * by Dj_Skual
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any
 * damages arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any
 * purpose, including commercial applications, and to alter it and
 * redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you
 * must not claim that you wrote the original software. If you use
 * this software in a product, an acknowledgment in the product
 * documentation would be appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and
 * must not be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source
 * distribution.
 *
 * MiiTools.cpp
 *
 * for SaveGame Manager GX 2012
 ***************************************************************************/
#include <stdio.h>
#include <string.h>
#include <malloc.h>

#include "MiiTools.h"
#include "../FileOperations/Nand.hpp"
#include "../Memory/MemTools.h"

//#include "../Tools/gecko.h"

/****************************************************************************
 * utf16fix()
 *
 * fix utf-16 name & creator of mii
 ***************************************************************************/
std::wstring MiiTools::utf16fix(u16* data, u32 size)
{
	wchar_t wdata[size];
	
	for (u32 i = 0; i < size; i++)
		wdata[i] = data[i];
	
	free(data);
	data = NULL;
	
	std::wstring utf16 = wdata;
	if(utf16.size() > size)
		utf16.resize(size);
	
	return utf16;
}

std::wstring MiiTools::GetDeviceName(std::string miipath)
{
	FILE *fp = fopen(miipath.c_str(),"rb");
	if(fp == NULL)
		return L"";
	
	u16* namedata = (u16*)memalign(32, 20);
	memset(namedata, 0, sizeof(namedata));
	
	fseek(fp , 2, SEEK_SET);
	fread(namedata,1,20,fp);
	fclose(fp);
	
	return utf16fix(namedata, 20);
}

std::wstring MiiTools::GetDeviceCreator(std::string miipath)
{
	FILE *fp = fopen(miipath.c_str(),"rb");
	if(fp == NULL)
		return L"";
	
	u16* creatordata = (u16*)memalign(32, 20);
	memset(creatordata, 0, sizeof(creatordata));
	
	fseek(fp , 0x36, SEEK_SET);
	fread(creatordata,1,20,fp);
	fclose(fp);
	
	return utf16fix(creatordata, 20);
}

/*std::wstring MiiTools::GetNandName(int position)
{
	int fh = Nand::OpenRead(MII_FILE);
	if (fh < 0)
		return L"";
	
	Nand::Seek(fh, MII_HEADER+0x02+(position*MII_SIZE), 0);
	u16* namedata = (u16*)MemTools::AllocateMemory_32(20);
	memset(namedata, 0, round_up(20, 32));
	
	if (Nand::Read(fh, (u8*)namedata, 20) < 0)
	{
		Nand::Close(fh);
		free(namedata);
		namedata = NULL;
		return L"";
	}
	Nand::Close(fh);
	
	std::wstring testname = utf16fix(namedata);
	//gprintf("\n\t MiiNandName = %s", wstr2str(testname).c_str());
	
	return testname;
}*/
 
/*std::wstring MiiTools::GetNandCreator(int position)
{
	int fh = Nand::OpenRead(MII_FILE);
	if (fh < 0)
		return L"";
	
	Nand::Seek(fh, MII_HEADER+0x36+(position*MII_SIZE), 0);
	u16* creatordata = (u16*)MemTools::AllocateMemory_32(20);
	memset(creatordata, 0, round_up(20, 32));
	
	if (Nand::Read(fh, (u8*)creatordata, 20) < 0)
	{
		Nand::Close(fh);
		free(creatordata);
		creatordata = NULL;
		return L"";
	}
	Nand::Close(fh);
	
	return utf16fix(creatordata);
}*/

static char * readDeviceMii(std::string path)
{
	FILE * File = fopen(path.c_str(), "rb");
	if (File == NULL)
		return NULL;
	
	char * buffer = (char*)malloc(74);
	fread(buffer, 1, 74, File);
	fclose(File);
	
	return buffer;
}

bool MiiTools::GetDeviceInfos(std::string miipath, MiiStruct * miiStruct, bool GetCreator, bool GetName)
{
	char * data = readDeviceMii(miipath);
	if (!data)
		return false;
	
	if(GetName)
	{
		u16* namedata = (u16*)memalign(32, 20);
		memset(namedata, 0, sizeof(namedata));
		memcpy(namedata, data+0x2, 20);
		
		miiStruct->name = utf16fix(namedata, 20);
	}
	if(GetCreator)
	{
		u16* creatordata = (u16*)memalign(32, 20);
		memset(creatordata, 0, sizeof(creatordata));
		memcpy(creatordata, data+0x36, 20);
		
		miiStruct->creator = utf16fix(creatordata, 20);
	}
	
	miiStruct->position = 0;
	
	if (data[0x00] & 1) miiStruct->day += 8;
	if (data[0x00] & 2) miiStruct->day += 16;
	if (data[0x01] & 32) miiStruct->day += 1;
	if (data[0x01] & 64) miiStruct->day += 2;
	if (data[0x01] & 128) miiStruct->day += 4;
	
	if (data[0x00] & 4) miiStruct->month += 1;
	if (data[0x00] & 8) miiStruct->month += 2;
	if (data[0x00] & 16) miiStruct->month += 4;
	if (data[0x00] & 32) miiStruct->month += 8;
	
	miiStruct->female = data[0x00] & 64;
	
	if (data[0x01] & 2) miiStruct->favColor += 1;
	if (data[0x01] & 4) miiStruct->favColor += 2;
	if (data[0x01] & 8) miiStruct->favColor += 4;
	if (data[0x01] & 16) miiStruct->favColor += 8;
	
	free(data);
	data = NULL;
	
	return true;
}

bool MiiTools::GetNandInfos(int position, char* data, MiiStruct * miiStruct)
{
	miiStruct->position = position;
	
	int start = position*MII_SIZE+MII_HEADER;
	
	u16* namedata = (u16*)MemTools::AllocateMemory_32(10);
	memset(namedata, 0, round_up(10, 32));
	memcpy(namedata, data+start+0x02, round_up(10, 32));
	
	miiStruct->name = utf16fix(namedata, 10);
	if(miiStruct->name.empty())
		return false;
	
	u16* creatordata = (u16*)MemTools::AllocateMemory_32(10);
	memset(creatordata, 0, round_up(10, 32));
	memcpy(creatordata, data+start+0x36, round_up(10, 32));
	
	miiStruct->creator = utf16fix(creatordata, 10);
	
	miiStruct->day = 0;

	if (data[start+0x00] & 1) miiStruct->day += 8;
	if (data[start+0x00] & 2) miiStruct->day += 16;

	miiStruct->month = 0;
	if (data[start+0x00] & 4) miiStruct->month += 1;
	if (data[start+0x00] & 8) miiStruct->month += 2;
	if (data[start+0x00] & 16) miiStruct->month += 4;
	if (data[start+0x00] & 32) miiStruct->month += 8;

	miiStruct->female = data[start+0x00] & 64;

	miiStruct->favColor = 0;
	if (data[start+0x01] & 2) miiStruct->favColor += 1;
	if (data[start+0x01] & 4) miiStruct->favColor += 2;
	if (data[start+0x01] & 8) miiStruct->favColor += 4;
	if (data[start+0x01] & 16) miiStruct->favColor += 8;

	if (data[start+0x01] & 32) miiStruct->day += 1;
	if (data[start+0x01] & 64) miiStruct->day += 2;
	if (data[start+0x01] & 128) miiStruct->day += 4;
	
	return true;
}

int MiiTools::FindFirstFree(Browser * browser)
{
	int pos = 0;
	int position = 0;
	int listCnt = browser->GetEntrieCount();
	
	for(position = 0; position < MII_MAX; position++)
	{
		bool freeSpaceOk = true;
		
		for(int n = 0; n < listCnt; n++)
		{
			pos = browser->GetMiiPosition(n);
			
			if(pos == position)
			{
				freeSpaceOk = false;
				break;
			}
		}
		if(freeSpaceOk == true)
			break;
	}
	
	return position;
}
